use bits::{BitsOps, IntoBits};

pub enum Code {
    // 在使用中断向量时，所有的异常都通过 0 向量转发。
    SupervisorSoftware = 1,
    MachineSoftware = 3,
    SupervisorTimer = 5,
    MachineTimer = 7,
    SupervisorExternal = 9,
    MachineExternal = 11,
}

/// 中断号，不编码最高 bit，最高 bit 的编码由 [`Cause`](crate::register::machine::mcause::Cause) 来进行
pub enum Interrupt {
    Reserved(usize),
    /// 平台自定义的异常码
    Platform(usize),
    /// 即 riscv 内核规定的异常码
    Core(Code),
}

impl TryFrom<usize> for Interrupt {
    type Error = &'static str;

    fn try_from(value: usize) -> Result<Self, Self::Error> {
        Ok(match value {
            1 => Interrupt::Core(Code::SupervisorSoftware),
            3 => Interrupt::Core(Code::MachineSoftware),
            5 => Interrupt::Core(Code::SupervisorTimer),
            7 => Interrupt::Core(Code::MachineTimer),
            9 => Interrupt::Core(Code::SupervisorExternal),
            11 => Interrupt::Core(Code::MachineExternal),
            _ => {
                if value.bits(..).msb() {
                    Err("msb must not be set")?
                } else if value <= 15 {
                    Interrupt::Reserved(value)
                } else {
                    Interrupt::Platform(value)
                }
            }
        })
    }
}

impl Into<usize> for Interrupt {
    fn into(self) -> usize {
        match self {
            Interrupt::Reserved(x) | Interrupt::Platform(x) => x,
            Interrupt::Core(x) => x as usize,
        }
    }
}
